home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
001-025
/
scopedisk16
/
cw11
/
cw.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-18
|
10KB
|
352 lines
/*
cw - one-shot stream editor
Version 1.1
Copyright (C) 1988 Daniel Elbaum
New in Version 1.1:
-Fixed an output buffering problem wherein
the i/o buffer got flushed twice (it's a
long way to CON: ;{))
-Fixed a case wherein a few bytes of memory
were left unfreed when the target file
couldn't be found.
-Added a special-case replacement string arg,
"\0", to specify a null replacement string.
This feature avoids difficulties with the
quoting/argument-parsing conventions of
various command interpreters.
*/
#include <stdio.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <exec/memory.h>
#ifndef BUFSIZ
#define BUFSIZ (512)
#endif
#define LSIZ (258)
#ifndef MIN
#define MIN(x, y) ((x)>(y)?(y):(x))
#endif
UBYTE iobuf[BUFSIZ];
int iosofar=0;
int nflag;
UBYTE *strchr(); /* defined in cwlib.asm */
#define ismeta(x) (strchr("*?.^$", (x)))
#define plur(x) ((x)==1?'\0':'s') /* pluralizes a number */
struct finfo {
UBYTE *name; /* file name */
UBYTE *mp; /* file buffer */
struct FileHandle *fh; /* file handle */
ULONG n; /* bytes in file */
};
main(c, v)
UBYTE *v[];
{
register n, usage=0;
register UBYTE **vp;
UBYTE sub[LSIZ], targ[LSIZ];
UBYTE obu[BUFSIZ];
if (c<4) usage++;
else if (v[1][0]=='-')
if (v[1][1]=='n'){
if (!v[1][2]) nflag=1;
else if (!(nflag=atoi(&(v[1][2])))) usage++;
v++;
}
else usage++;
if (usage){
puts("Usage: cw [-nN] target replacement files...");
puts("N is the maximum number of substitutions to make");
exit(-1);
}
prepstrings(v[1], v[2], targ, sub); /* map metachars */
for (vp=&v[3]; *vp; ++vp){
strcpy(obu, *vp);
strcat(obu, ": ");
fputs(obu, stdout);
n=cw(targ, sub, *vp);
if (n>=0){
sprintf(obu, "%d change%c", n, plur(n));
puts(obu);
}
else puts("error");
}
if (n<0) exit(-1);
exit(0);
}
cw(ip, op, nam)
register UBYTE *ip, *op;
UBYTE *nam;
{
register UBYTE *iop;
register ULONG n;
register struct FileHandle *fh;
register ilen;
register rpt;
int olen;
int nchanges=0;
struct finfo f;
olen=strlen(op);
setmem(&f, sizeof(f), '\0');
f.name=nam;
if (fillbuf(&f)<0) {cleanup(&f); return(-1);}
if (!(rpt=nflag)) rpt=-1;
iop=f.mp;
n=f.n;
fh=f.fh;
while (n){
if (rpt&&(ilen=regcmp(ip, iop))){
if (bufout(fh, op, olen)){
puts("write error--FILE TRASHED");
return(-1);
}
iop+=ilen;
n-=ilen;
if (n<0) puts("DS error");
nchanges++;
if (rpt>0) if (nchanges>=rpt) rpt=0;
}
else {
if (bufout(fh, iop++, 1)) puts("write error");
--n;
}
}
cleanup(&f);
return(nchanges);
}
cleanup(sp)
struct finfo *sp;
{
Write(sp->fh, iobuf, iosofar); /* flush output buffer */
iosofar=0;
if (sp->fh) Close(sp->fh);
if (sp->mp) FreeMem(sp->mp, sp->n);
}
prepstrings(ip, op, ipbu, opbu)
UBYTE *ip, *op;
register UBYTE *opbu, *ipbu;
{
register UBYTE *foop;
register hat=0, cash=0;
/* special case: op = "\0" */
if (op[0]=='\\'&&op[1]=='0'&&op[2]=='\0') op[0]='\0';
/* special case: target=='^$' */
if ((ip[0]=='^')&&(ip[1]=='$')&&(ip[2]=='\0')){
movmem(ipbu, "\n\n\0", 3);
*opbu='\n'; opbu[1]='\0';
if (strlen(op)){
strcat(opbu, op);
strcat(opbu, "\n");
}
}
strcpy(ipbu, ip);
escape(ipbu);
/* ... and here's something for the commoners */
for (foop=ipbu; *foop; ++foop)
if (*foop==0xDE) {++hat; *foop='\n';}
else if (*foop==0xA4) {++cash; *foop='\n';}
if (hat) *opbu++ = '\n';
*opbu='\0';
strcat(opbu, op);
if (cash) strcat(opbu, "\n");
return(0);
}
/*
set high bit of non-escaped metacharacters
and convert escape sequences
*/
escape(s)
register UBYTE *s;
{
UBYTE bu[256];
register UBYTE *op;
register esc, i, c;
op=s;
for (esc=i=0; *s; ++s){
if (!esc){
if (ismeta(*s)) bu[i++]=*s|0x80;
else if (*s=='\\') ++esc;
else bu[i++]=*s;
continue;
}
else{
switch(*s){
case 't': c='\t'; break;
case 'n': c='\n'; break;
case 'r': c='\r'; break;
case 'b': c='\b'; break;
case 'f': c='\f'; break;
default: c=*s;
}
bu[i++]=c;
esc=0;
}
}
bu[i]='\0';
strcpy(op, bu);
return(0);
}
/*
Hand-buffer output.
Works for cnt==0; theoretically for cnt>BUFSIZ.
*/
bufout(fh, buf, cnt)
register struct FileHandle *fh;
register UBYTE *buf;
register cnt;
{
register n=0, off;
do{
off=n; /* keep track of #chars written */
cnt-=n; /* subtract #written from # to write */
n=MIN(cnt, BUFSIZ-iosofar); /* chunk to put in iobu */
movmem(buf+off, iobuf+iosofar, n);
iosofar+=n;
if (iosofar>=BUFSIZ){
if (Write(fh, iobuf, iosofar)<0) return(-1);
iosofar=0;
}
} while (cnt);
return(0);
}
/*
Allocate space for a whole-file buffer, fill it,
then truncate the file and open for writing.
Name passed in sp->name;
File handle returned in sp->fh;
Length of file returned in sp->n;
Address of buffer returned in sp->mp;
*/
fillbuf(sp)
register struct finfo *sp;
{
register fibsiz;
struct FileLock *l;
struct FileInfoBlock *fi;
UBYTE *AllocMem();
struct FileHandle *Open();
struct FileLock *Lock();
fibsiz=sizeof(struct FileInfoBlock);
if (!(fi=(struct FileInfoBlock *)AllocMem(fibsiz, MEMF_PUBLIC)))
return(-1);
if (!(l=Lock(sp->name, ACCESS_WRITE))) {
FreeMem(fi, fibsiz);
return(-1);
}
if (!(Examine(l, fi))) {FreeMem(fi, fibsiz); UnLock(l); return(-1);}
sp->n=fi->fib_Size;
FreeMem(fi, fibsiz);
UnLock(l);
if (!(sp->mp=AllocMem(sp->n, MEMF_PUBLIC))) return(-1);
if (!(sp->fh=Open(sp->name, MODE_OLDFILE))){
FreeMem(sp->mp, sp->n);
return(-1);
}
if (Read(sp->fh, sp->mp, sp->n)!=sp->n){
Close(sp->fh);
FreeMem(sp->mp, sp->n);
return(-1);
}
Close(sp->fh);
if (!(sp->fh=Open(sp->name, MODE_NEWFILE))) {
FreeMem(sp->mp, sp->n);
return(-1);
}
return(0);
}
regcmp(p1, p2)
register UBYTE *p1, *p2;
{
register len;
register out=0;
for (len=0; p2[len]; ++p1, ++len){
if (!(*p1)) break;
if (!(*p1&0x80))
if (regchar(*p1, p2[len])) {len=0; break;}
else continue;
switch(*p1&0xFF){
case 0xAA: /* * */
if (!*++p1) {++out; break;}
while (p2[len]&®char(*p1, p2[len]))
++len;
if (!p2[len]) ++out;
break;
case 0xBF: /* ? */
break;
case 0xAE: /* . */
if (p2[len]!=' ') break;
default: /* AE may fall through */
len=0; ++out;
break;
}
if (out) break;
}
if (*p1) len=0;
return(len);
}
/*
0 means c1 matches c2
*/
regchar(c1, c2)
register c1, c2;
{
if (c1==c2) return(0);
if ((c1=='\n'||c1=='\r')&&(c2=='\n'||c2=='\r')) return(0);
if (!(c1&0x80)) return(1);
switch(c1&0xFF){
case 0xAA: /* *--falls through */
case 0xBF: /* ? */
return(0);
case 0xAE: /* .--falls through */
if (c2!=' ') return(0);
default:
return(1);
}
/* NOTREACHED */
}
UBYTE *
strchr(s, c)
UBYTE *s;
{
if (s)
while (*s)
if (*s==c) return(s);
else s++;
return(NULL);
}